#import "HttpServer.h"
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonKeyDerivation.h>
#import <CommonCrypto/CommonDigest.h>

@implementation HttpServer : NSObject

- (void)sendPOSTRequestWithURLString:(NSString *)urlString postData:(NSDictionary *)postDictionary key:(NSString *)key pName:(NSString *)pName completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler {
    NSURL *url = [NSURL URLWithString:urlString];
    
    if (!url) {
        NSError *urlError = [NSError errorWithDomain:@"InvalidURL" code:1001 userInfo:@{NSLocalizedDescriptionKey: @"Invalid URL."}];
        completionHandler(nil, nil, urlError);
        return;
    }
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setValue:pName forHTTPHeaderField:@"Product"];
    
    NSError *jsonError;
    NSData *postData = [NSJSONSerialization dataWithJSONObject:postDictionary options:0 error:&jsonError];
    if (!postData) {
        completionHandler(nil, nil, jsonError);
        return;
    }
    
    NSString *stringFromData = [[NSString alloc] initWithData:postData encoding:NSUTF8StringEncoding];
    NSString *encodedString = [self encodeContent:stringFromData withKey:key];
    
    if (!encodedString) {
        NSError *encodingError = [NSError errorWithDomain:@"EncodingError" code:1002 userInfo:@{NSLocalizedDescriptionKey: @"Failed to encode content."}];
        completionHandler(nil, nil, encodingError);
        return;
    }
    
    NSData *encodedData = [encodedString dataUsingEncoding:NSUTF8StringEncoding];
    
    
    [request setHTTPBody:encodedData];
    
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:completionHandler];
    [dataTask resume];
}

- (NSString *)encodeContent:(NSString *)content withKey:(NSString *)key {
    NSString *ivKey = [key substringToIndex:MIN(16, key.length)];
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *ivData = [ivKey dataUsingEncoding:NSUTF8StringEncoding];
    NSData *contentData = [content dataUsingEncoding:NSUTF8StringEncoding];
    
    size_t bufferSize = contentData.length + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesEncrypted = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          keyData.bytes,
                                          kCCKeySizeAES256,
                                          ivData.bytes,
                                          contentData.bytes,
                                          contentData.length,
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    
    if (cryptStatus == kCCSuccess) {
        NSData *encryptedData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        return [encryptedData base64EncodedStringWithOptions:0];
    }
    
    free(buffer);
    return nil;
}

- (NSString *)decodeContent:(NSString *)content withKey:(NSString *)key {
    NSString *ivKey = [key substringToIndex:MIN(16, key.length)];
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *ivData = [ivKey dataUsingEncoding:NSUTF8StringEncoding];
    NSData *contentData = [[NSData alloc] initWithBase64EncodedString:content options:NSDataBase64DecodingIgnoreUnknownCharacters];
    
    size_t bufferSize = contentData.length + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesDecrypted = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          keyData.bytes,
                                          kCCKeySizeAES256,
                                          ivData.bytes,
                                          contentData.bytes,
                                          contentData.length,
                                          buffer,
                                          bufferSize,
                                          &numBytesDecrypted);
    
    if (cryptStatus == kCCSuccess) {
        NSString *decryptedString = [[NSString alloc] initWithBytes:buffer length:numBytesDecrypted encoding:NSUTF8StringEncoding];
        free(buffer);
        return decryptedString;
    }
    
    free(buffer);
    return nil;
}

@end
